﻿import net.sourceforge.chart2d.*;

import java.awt.*;
import java.util.*;
import java.util.List;


public class ChartImage {
    private String chartName = "Changing Price";
    private String[] legengLables = {"2007"};
    private String[] bottomAxisLabels = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    private String topAxisName = "Price, $";
    private String bottomAxisName = "Month";
    private Dataset dataSet = null;
    private Dimension dimension = null;

    private Integer setValuesNum = 0;
    private Integer categoryValuesNum = 0;
    private Integer itemValuesNum = 0;
    private Integer maxItemValue = 0;

    public Chart2D getChart2DDemoK() {

        //<-- Begin Chart2D configuration -->
        //Configure object properties
        Object2DProperties object2DProps = new Object2DProperties();
        object2DProps.setObjectTitleText(chartName);

//Configure chart properties
        Chart2DProperties chart2DProps = new Chart2DProperties();
        chart2DProps.setChartDataLabelsPrecision(1);

//Configure legend properties
        LegendProperties legendProps = new LegendProperties();
        legendProps.setLegendLabelsTexts(legengLables);

//Configure graph chart properties
        GraphChart2DProperties graphChart2DProps = new GraphChart2DProperties();
        graphChart2DProps.setLabelsAxisLabelsTexts(bottomAxisLabels);
        graphChart2DProps.setLabelsAxisTitleText(bottomAxisName);
        graphChart2DProps.setNumbersAxisTitleText(topAxisName);
        graphChart2DProps.setLabelsAxisTicksAlignment(graphChart2DProps.CENTERED);

        //graphChart2DProps.setChartDatasetCustomGreatestValue(1000000);
        //graphChart2DProps.setChartDatasetCustomizeGreatestValue(true);

//Configure graph properties
        GraphProperties graphProps = new GraphProperties();
        graphProps.setGraphBarsExistence(false);
        graphProps.setGraphLinesExistence(true);
        graphProps.setGraphLinesThicknessModel(1);
        graphProps.setGraphLinesWithinCategoryOverlapRatio(1f);
        graphProps.setGraphDotsExistence(false);
        graphProps.setGraphDotsThicknessModel(10);
        graphProps.setGraphDotsWithinCategoryOverlapRatio(1f);
        graphProps.setGraphAllowComponentAlignment(false);

        //Configure dataset
        if (dataSet == null) {
            Random random = new Random();
            dataSet = new Dataset(1, 48, 1);
            for (int i = 0; i < dataSet.getNumSets(); ++i) {
                for (int j = 0; j < dataSet.getNumCats(); ++j) {
                    for (int k = 0; k < dataSet.getNumItems(); ++k) {
                        int increaseMetric = dataSet.getNumSets() - i - 1;
                        dataSet.set(i, j, k,
                                (increaseMetric + 1) * random.nextInt(5) * 5 + (increaseMetric + 1) * 30 + j * 3);
                    }
                }
            }
        }
        //Configure graph component colors
        MultiColorsProperties multiColorsProps = new MultiColorsProperties();
        multiColorsProps.setColorsType(MultiColorsProperties.NATURAL);
//Configure chart
        LBChart2D chart2D = new LBChart2D();
        chart2D.setObject2DProperties(object2DProps);
        chart2D.setChart2DProperties(chart2DProps);
        chart2D.setLegendProperties(legendProps);
        chart2D.setGraphChart2DProperties(graphChart2DProps);
        chart2D.addGraphProperties(graphProps);
        chart2D.addDataset(dataSet);
        chart2D.addMultiColorsProperties(multiColorsProps);
        chart2D.setPreferredSize(dimension);
//Optional validation:  Prints debug messages if invalid only.
        // if (!chart2D.validate(false)) chart2D.validate(true);

//<-- End Chart2D configuration -->

        return chart2D;
    }

    public String getChartName() {
        return chartName;
    }

    public void setChartName(String chartName) {
        this.chartName = chartName;
    }

    public String[] getLegengLables() {
        return legengLables;
    }

    public void setLegengLables(String[] legengLables) {
        this.legengLables = legengLables;
    }

    public String[] getBottomAxisLabels() {
        return bottomAxisLabels;
    }

    public void setBottomAxisLabels(String[] bottomAxisLabels) {
        this.bottomAxisLabels = bottomAxisLabels;
    }

    public String getTopAxisName() {
        return topAxisName;
    }

    public void setTopAxisName(String topAxisName) {
        this.topAxisName = topAxisName;
    }

    public String getBottomAxisName() {
        return bottomAxisName;
    }

    public void setBottomAxisName(String bottomAxisName) {
        this.bottomAxisName = bottomAxisName;
    }

    public Dataset getDataSet() {
        return dataSet;
    }

    public void setDataSet(Dataset dataSet) {
        this.dataSet = dataSet;
    }

    public void setDimension(Integer width, Integer height) {
        if (height != null && width != null && height > 0 && width > 0) {
            dimension = new Dimension(width, height);
        }
    }

    public List<Map> fillByValue(Calendar cal, Calendar lastCal, Double value) {
        List<Map> priceStatisticFrgment = new ArrayList<Map>();
        while (cal.get(Calendar.DAY_OF_MONTH) > lastCal.get(Calendar.DAY_OF_MONTH) || cal.get(Calendar.MONTH) > lastCal.get(Calendar.MONTH) || cal.get(Calendar.YEAR) > lastCal.get(Calendar.YEAR)) {
            lastCal.add(Calendar.DAY_OF_MONTH, 1);
            Map map = new HashMap();
            map.put("year", lastCal.get(Calendar.YEAR));
            map.put("month", lastCal.get(Calendar.MONTH) + 1);
            map.put("day", lastCal.get(Calendar.DAY_OF_MONTH));
            map.put("price", value);
            if (priceStatisticFrgment.size() > 1) {
                Map lastAdded = priceStatisticFrgment.get(priceStatisticFrgment.size() - 1);
                Integer lastAddedDayValue = ((Integer) lastAdded.get("day"));
                Integer curDayValue = lastCal.get(Calendar.DAY_OF_MONTH);
                if (lastAddedDayValue > curDayValue && lastAddedDayValue < 31) {
                    for (int i = lastAddedDayValue+1; i <= 31; i++) {
                        Map subMap = new HashMap();
                        subMap.put("year", lastAdded.get("year"));
                        subMap.put("month", lastAdded.get("month"));
                        subMap.put("day", i);
                        subMap.put("price", lastAdded.get("price"));
                        priceStatisticFrgment.add(subMap);
                        System.out.println("--" + value + "-- " + i + " >= " + 31 + " |-| " + (lastCal.get(Calendar.MONTH) + 1) + " >= " + (lastCal.get(Calendar.MONTH) + 1) + " |-| " + lastCal.get(Calendar.YEAR) + " >= " + lastCal.get(Calendar.YEAR));
                    }
                }
            }
            priceStatisticFrgment.add(map);
            System.out.println("--" + value + "-- " + cal.get(Calendar.DAY_OF_MONTH) + " >= " + lastCal.get(Calendar.DAY_OF_MONTH) + " |-| " + (cal.get(Calendar.MONTH) + 1) + " >= " + (lastCal.get(Calendar.MONTH) + 1) + " |-| " + cal.get(Calendar.YEAR) + " >= " + lastCal.get(Calendar.YEAR));


        }

        return priceStatisticFrgment;

    }

    public void convertToDataSet(List dataList) {
        List<Map> priceStatistic = new ArrayList<Map>();
        Integer lastState = null;
        Date lastDate = null;
        for (Object aDataList : dataList) {
            Map data = (Map) aDataList;
            Integer state = (Integer) data.get("state");
            Double price = (Double) data.get("priceValue");
            Date date = (Date) data.get("date");
            Calendar cal = new GregorianCalendar();
            cal.setTime(date);
            switch (state) {
                case 0:
                    if (lastState != null && lastDate != null && lastDate.compareTo(date) < 0) {
                        Calendar lastCal = new GregorianCalendar();
                        lastCal.setTime(lastDate);
                        priceStatistic.addAll(fillByValue(cal, lastCal, price));
                        break;
                    }
                case -1:
                    if (lastState != null && lastDate != null && lastDate.compareTo(date) < 0) {
                        Calendar lastCal = new GregorianCalendar();
                        lastCal.setTime(lastDate);
                        priceStatistic.addAll(fillByValue(cal, lastCal, price));
                    }
                    break;

                case 1:
                    Map map = new HashMap();
                    map.put("year", cal.get(Calendar.YEAR));
                    map.put("month", cal.get(Calendar.MONTH) + 1);
                    map.put("day", cal.get(Calendar.DAY_OF_MONTH));
                    map.put("price", price);

                    priceStatistic.add(map);
                    break;
            }
            lastState = state;
            lastDate = date;

            System.out.println("!" + state + "--" + price + "--" + date);
        }
        fillCorrectDataSet(priceStatistic, "year", "month", "day", "price");
    }

    public void fillCorrectDataSet(List dataList, String set, String category, String item, String value) {
        List<String> categoryLabels = new ArrayList<String>();
        List<String> setLabels = new ArrayList<String>();

        Double dataValue = 0d;

        int setIntValue = 0;
        int categoryIntValue = 0;
        int itemIntValue = 0;

        int firstSetIntValue = 0;
        int firstCategoryIntValue = 0;
        Integer yearsNum = 0;
        Integer monthsNum = 0;
        Map first = (Map)dataList.get(0);
        Map last = (Map)dataList.get(dataList.size()-1);
        yearsNum = Integer.parseInt(last.get(set).toString()) - Integer.parseInt(first.get(set).toString());
        monthsNum = Integer.parseInt(last.get(category).toString()) - Integer.parseInt(first.get(category).toString());
        dataSet = new Dataset(yearsNum+1, (monthsNum+1) + (yearsNum*12), 31);
        for (int i = 0; i < dataList.size(); i++) {
            Object obj = dataList.get(i);
            Object setDbValue = null;
            Object categoryDbValue = null;
            Object itemDbValue = null;
            Object dataDbValue = null;
            if (obj instanceof Map) {
                Map dataMap = (Map) obj;
                setDbValue = dataMap.get(set);
                categoryDbValue = dataMap.get(category);
                itemDbValue = dataMap.get(item);
                dataDbValue = dataMap.get(value);
            } else if (obj instanceof List) {
                List paramList = (List) obj;
                setDbValue = paramList.get(0);
                categoryDbValue = paramList.get(1);
                itemDbValue = paramList.get(2);
                dataDbValue = paramList.get(3);
            }

            if (setDbValue != null) {
                try {
                    setIntValue = Integer.parseInt(setDbValue.toString());
                } catch (Exception e) {
                }
            }
            //System.out.println(setIntValue+"--"+setDbValue instanceof String);
            if (categoryDbValue != null)
                try {
                    categoryIntValue = Integer.parseInt(categoryDbValue.toString());
                } catch (Exception e) {
                }

            if (itemDbValue != null)
                try {
                    itemIntValue = Integer.parseInt(itemDbValue.toString());
                } catch (Exception e) {
                }
            if (dataDbValue != null)
                try {
                    dataValue = Double.parseDouble(dataDbValue.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            if (!setLabels.contains(setDbValue.toString())) {
                setLabels.add("" + setDbValue);
            }
            if (!categoryLabels.contains(categoryDbValue.toString())) {
                categoryLabels.add("" + categoryDbValue);
            }

            if(i == 0){
                firstSetIntValue = setIntValue;
                firstCategoryIntValue = categoryIntValue;
            }


            dataSet.set(setIntValue - firstSetIntValue, categoryIntValue - firstCategoryIntValue, itemIntValue-1, dataValue.floatValue());
            System.out.println((setIntValue - firstSetIntValue) + "<->" + (categoryIntValue - firstCategoryIntValue) + "<->" + (itemIntValue-1) + "<->" + dataValue.floatValue());
        }

        setLegengLables(setLabels.toArray(new String[setLabels.size()]));
        setBottomAxisLabels(categoryLabels.toArray(new String[categoryLabels.size()]));
        System.out.println("!!!!!!");

    }

    public void fillDataSet(List dataList, String set, String category, String item, String value, boolean pullTails) {
        List<String> categoryLabels = new ArrayList<String>();
        List<String> setLabels = new ArrayList<String>();

        int setIndex = 0;
        int lastSetIndex = 0;
        int categoryIndex = 0;
        int lastCategoryIndex = 0;
        int itemIndex = 0;
        int lastItemIndex = 0;

        Double dataValue = 0d;
        Double lastDataValue = 0d;

        int setIntValue = 0;
        int categoryIntValue = 0;
        int itemIntValue = 0;

        int lastSetIntValue = 0;
        int lastCategoryIntValue = 0;
        int lastItemIntValue = 0;

        System.out.println("Counting setsValues....");
        countDataSetValues(dataList, set, category, item, value);
        System.out.println("setsValues is: setValuesNum = " + setValuesNum + " categoryValuesNum = " + categoryValuesNum + " itemValuesNum = " + itemValuesNum + " maxItemValue = " + maxItemValue);
        if (maxItemValue < 28)
            maxItemValue = 31;
        else
            maxItemValue++;
        if (itemValuesNum < maxItemValue)
            itemValuesNum = maxItemValue;
        dataSet = new Dataset(setValuesNum, categoryValuesNum, itemValuesNum);

        /*Integer setNum = 0;
        Integer categoryNum = 0;
        Map first = (Map)dataList.get(0);
        Map last = (Map)dataList.get(dataList.size()-1);
        setNum = Integer.parseInt(last.get(set).toString()) - Integer.parseInt(first.get(set).toString());
        categoryNum = Integer.parseInt(last.get(category).toString()) - Integer.parseInt(first.get(category).toString());
        maxItemValue = 32;
        dataSet = new Dataset(setNum+2, (categoryNum+1) + (setNum*12), 32);
          */

        for (int i = 0; i < dataList.size(); i++) {
            Object obj = dataList.get(i);
            Object setDbValue = null;
            Object categoryDbValue = null;
            Object itemDbValue = null;
            Object dataDbValue = null;
            if (obj instanceof Map) {
                Map dataMap = (Map) obj;
                setDbValue = dataMap.get(set);
                categoryDbValue = dataMap.get(category);
                itemDbValue = dataMap.get(item);
                dataDbValue = dataMap.get(value);
            } else if (obj instanceof List) {
                List paramList = (List) obj;
                setDbValue = paramList.get(0);
                categoryDbValue = paramList.get(1);
                itemDbValue = paramList.get(2);
                dataDbValue = paramList.get(3);
            }

            if (setDbValue != null) {
                try {
                    setIntValue = Integer.parseInt(setDbValue.toString());
                } catch (Exception e) {
                }
            }
            //System.out.println(setIntValue+"--"+setDbValue instanceof String);
            if (categoryDbValue != null)
                try {
                    categoryIntValue = Integer.parseInt(categoryDbValue.toString());
                } catch (Exception e) {
                }

            if (itemDbValue != null)
                try {
                    itemIntValue = Integer.parseInt(itemDbValue.toString()) - 1;
                } catch (Exception e) {
                }
            if (dataDbValue != null)
                try {
                    dataValue = Double.parseDouble(dataDbValue.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            if (!setLabels.contains(setDbValue.toString())) {
                setLabels.add("" + setDbValue);
            }
            if (!categoryLabels.contains(categoryDbValue.toString())) {
                categoryLabels.add("" + categoryDbValue);
            }

            if (i == 0) {
                lastSetIntValue = setIntValue;
                lastCategoryIntValue = categoryIntValue;
                itemIndex = itemIntValue;
            }

            if (setIntValue != lastSetIntValue){
                setIndex++;
            }
            if (categoryIntValue != lastCategoryIntValue)
                categoryIndex++;
            if (itemIntValue != lastItemIntValue)
                itemIndex++;

            if (setIntValue != lastSetIntValue) {
                categoryIndex = 0;
            }
            if (categoryIntValue != lastCategoryIntValue) {
                itemIndex = itemIntValue;
            }

            if (itemIntValue == lastItemIntValue && categoryIntValue == lastCategoryIntValue && setIntValue == lastSetIntValue){
                continue;
            }

            if ((setIntValue == lastSetIntValue || pullTails) && categoryIntValue != lastCategoryIntValue && lastItemIndex + 1 < itemValuesNum) {
                System.out.println("-------");
                for (int j = lastItemIndex + 1; j < itemValuesNum; j++) {
                    dataSet.set(lastSetIndex, lastCategoryIndex, j, lastDataValue.floatValue());
                    System.out.println(lastSetIndex + "<->" + lastCategoryIndex + "<->" + j + "<->" + lastDataValue.floatValue());
                }
                System.out.println("+-----+");
            }
            if (itemIntValue > itemIndex) {
                System.out.println("+++++++");
                for (int j = itemIndex; j < itemIntValue; j++) {
                    dataSet.set(setIndex, categoryIndex, j, dataValue.floatValue());
                    System.out.println(setIndex + "<->" + categoryIndex + "<->" + j + "<->" + dataValue.floatValue());
                }
                itemIndex = itemIntValue;
                System.out.println("-+++++-");
            }


            dataSet.set(setIndex, categoryIndex, itemIndex, dataValue.floatValue());
//            if(setValuesNum == 1 && categoryValuesNum == 1 && itemValuesNum == 1)
//                dataSet.add(setIndex, categoryIndex, itemIndex+1, dataValue.floatValue());
            System.out.println(setIndex + "<->" + categoryIndex + "<->" + itemIndex + "<->" + dataValue.floatValue());
            lastSetIntValue = setIntValue;
            lastCategoryIntValue = categoryIntValue;
            lastItemIntValue = itemIntValue;
            lastDataValue = dataValue;
            lastItemIndex = itemIndex;
            lastSetIndex = setIndex;
            lastCategoryIndex = categoryIndex;

        }

        if (pullTails && lastItemIndex + 1 < itemValuesNum) {
            System.out.println("======");
            for (int j = lastItemIndex + 1; j < itemValuesNum; j++) {
                dataSet.set(lastSetIndex, lastCategoryIndex, j, lastDataValue.floatValue());
                System.out.println(lastSetIndex + "<->" + lastCategoryIndex + "<->" + j + "<->" + lastDataValue.floatValue());
            }
            System.out.println("*====*");
        }

        setLegengLables(setLabels.toArray(new String[setLabels.size()]));
        setBottomAxisLabels(categoryLabels.toArray(new String[categoryLabels.size()]));
        System.out.println("!!!!!!");

    }

    private void countDataSetValues(List dataList, String set, String category, String item, String value) {
        List setList = new ArrayList();
        List categoryList = new ArrayList();
        List itemList = new ArrayList();
        int itemIntValue = 0;
        for (int i = 0; i < dataList.size(); i++) {
            Object obj = dataList.get(i);
            Object setDbValue = null;
            Object categoryDbValue = null;
            Object itemDbValue = null;
            if (obj instanceof Map) {
                Map dataMap = (Map) obj;
                setDbValue = dataMap.get(set);
                categoryDbValue = dataMap.get(category);
                itemDbValue = dataMap.get(item);
            } else if (obj instanceof List) {
                List paramList = (List) obj;
                setDbValue = paramList.get(0);
                categoryDbValue = paramList.get(1);
                itemDbValue = paramList.get(2);
            }
            if (setDbValue == null)
                setDbValue = "0";
            if (categoryDbValue == null)
                categoryDbValue = "0";
            if (itemDbValue == null)
                itemDbValue = "0";
            if (!setList.contains(setDbValue.toString())) {
                setList.add(setDbValue.toString());
            }
            if (!categoryList.contains(categoryDbValue.toString())) {
                categoryList.add(categoryDbValue.toString());
            }
            if (!itemList.contains(itemDbValue.toString())) {
                itemList.add(itemDbValue.toString());
            }

            if (itemDbValue != null) {
                try {
                    itemIntValue = Integer.parseInt(itemDbValue.toString());
                } catch (Exception e) {
                }
                if (maxItemValue < itemIntValue) {
                    maxItemValue = itemIntValue;
                }
            }
        }

        setValuesNum = setList.size();
        categoryValuesNum = categoryList.size();
        itemValuesNum = itemList.size();
    }

}
